package com.guodi.model.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.guodi.common.utils.UuidUtil;
import com.guodi.common.utils.WordUtil;
import com.guodi.core.minio.util.MinioUtil;
import com.guodi.model.dto.IdtEstimateResultDto;
import com.guodi.model.entity.*;
import com.guodi.model.mapper.CmeReportMapper;
import com.guodi.model.mapper.IdtIndicatorsDirMapper;
import com.guodi.model.mapper.IdtMonitorValueMapper;
import com.guodi.model.service.*;
import com.guodi.model.utils.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @描述：体检报告管理表 服务类
 * @作者: 徐金洲
 * @日期: 2023-04-07
 */
@Service
public class CmeReportServiceImpl extends ServiceImpl<CmeReportMapper, CmeReport> implements ICmeReportService {

    @Resource
    private IIdtIndicatorsTypeService iIdtIndicatorsTypeService;

    @Resource
    private IIdtIndicatorsService iIdtIndicatorsService;

    @Resource
    private IIdtIndicatorsDirService idtIndicatorsDirService;

    @Resource
    private IIdtMonitorValueService idtMonitorValueService;

    @Resource
    private ICmeReportService cmeReportService;

    @Resource
    private CmeReportMapper cmeReportMapper;

    @Resource
    private IdtIndicatorsDirMapper idtIndicatorsDirMapper;

    @Resource
    private IdtMonitorValueMapper idtMonitorValueMapper;

    @Value("${upload.tempFilePath}")
    private String tempFilePath;


    @Override
    public void generateCmeReport(HttpServletResponse response, String indicatorsTypeCode, String divisionCode, Integer year, String orgId, String particularYear, CmeReport cmeReport,String imageArray) throws IOException {
        List<IdtEstimateResultDto> IdtEstimateResultDtos = this.idtIndicatorsDirService.getEstimateResults(indicatorsTypeCode,divisionCode,year.toString());
        String divisionText = idtMonitorValueService.getNameByDivisionCode(divisionCode);
        //定义文件存放路径
        String docxFileUrl = null;
        try{
            //文件名
            String newExportFileName = year.toString()+ "年" + divisionText+"城市体检评估报告" ;
            //word文档
            Map<String,Object> docxListInfo = this.generateCmeReportWord(IdtEstimateResultDtos, divisionCode, year, imageArray);
            docxFileUrl = FileUtil.tempFilePath + docxListInfo.get("docName");
            //保存文件信息
            InputStream inputStream = new FileInputStream(docxFileUrl);
            cmeReport.setDivisionName(divisionText);
            cmeReport.setDivisionCode(divisionCode);
            cmeReport.setReportName(newExportFileName);
            cmeReport.setYear(year.toString());
            cmeReport.setTypeValue("本报告包含" + docxListInfo.get("zbSize") + "项体检指标");
            //将word转成pdf,并上传文件
            uploadWordAndPdf(inputStream, cmeReport, docxFileUrl);
            //关闭输入流
            inputStream.close();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(docxFileUrl != null){
                FileUtil.deleteFile(docxFileUrl);
            }
        }
    }


    @Override
    public Boolean exportCmeReportReport(HttpServletResponse response, String indicatorsTypeCode, String divisionCode, Integer year, String orgId, String particularYear, CmeReport cmeReport) throws IOException {
        Boolean temp = false;
        // 获取行政区划
        String divisionText = this.idtMonitorValueService.getNameByDivisionCode(divisionCode);
        //获取根据编码获取体系类型
        IdtIndicatorsType one = iIdtIndicatorsTypeService.findByCode(indicatorsTypeCode, particularYear, divisionCode);
        //获取父节点下的所有数据
        List<ApiIdtIndicatorsDir> indicatorsDirList = idtIndicatorsDirService.listDirByCode(one.getId(), null,null);
        //提取目录
        List<ApiIdtIndicatorsDir> apiIdtIndicatorsDirs = indicatorsDirList.stream().filter(idtDir -> { return idtDir.getType() == 1; }).collect(Collectors.toList());
        //提取复合指标的数据
        //定义一个新的list 存储选择的复合指标
        List<String> listids = new ArrayList<>();
        listids.add("e5b85b9fc27c4abf81520aef137f479b");
        listids.add("291614804a3f4cb19a583fa331fa31a0");
        List<ApiIdtIndicatorsDir> fhzbList = new ArrayList<>();
        for(ApiIdtIndicatorsDir dir : indicatorsDirList){
            if(dir.getType() == 2 && dir.getIdtDatasource().equals("formula") && listids.contains(dir.getId())){
            //if(dir.getType() == 2 && dir.getIdtDatasource().equals("formula")){
                fhzbList.add(dir);
            }
        }
        apiIdtIndicatorsDirs.addAll(fhzbList);
        // 排序
        List<ApiIdtIndicatorsDir> indicatorsDirLists = SortUtil.sortList(apiIdtIndicatorsDirs, one.getId(), 1);
        // 查询所有指标
        List<IdtIndicators> allIdtList = iIdtIndicatorsService.list();
        // 因子列表
        List<ApiIdtIndicatorsDir> relIdtList = new LinkedList<>();
        // 因子id列表
        List<String> relIdtIdList = new LinkedList<>();
        for (ApiIdtIndicatorsDir apiIdtIndicatorsDir : indicatorsDirLists) {
            for (IdtIndicators idtIndicator : allIdtList) {
                // 条件：指标类型 + 计算公式不为空 + 计算公式包含这个指标
                if (apiIdtIndicatorsDir.getType() == 2 && org.apache.commons.lang.StringUtils.isNotBlank(apiIdtIndicatorsDir.getCalculateResult())
                        && apiIdtIndicatorsDir.getCalculateResult().indexOf(idtIndicator.getCode()) !=  -1) {
                    List<ApiIdtIndicatorsDir> calculateResultLit = null;
                    if (apiIdtIndicatorsDir.getCalculateResultLit() == null) {
                        calculateResultLit = new ArrayList<>();
                    } else {
                        calculateResultLit = apiIdtIndicatorsDir.getCalculateResultLit();
                    }
                    ApiIdtIndicatorsDir relDir = new ApiIdtIndicatorsDir();
                    relDir.setId(idtIndicator.getId());
                    relDir.setIndicatorsId(idtIndicator.getId());
                    relDir.setType(2);
                    relDir.setIdtCalculateSource(apiIdtIndicatorsDir.getIdtCalculateSource());
                    relDir.setIdtConnotation(idtIndicator.getConnotation());
                    relDir.setIdtCode(idtIndicator.getCode());
                    relDir.setIdtCalculateUnit(idtIndicator.getCalculateUnit());
                    relDir.setIdtDutyDepartment(idtIndicator.getDutyDepartment());
                    relDir.setIdtDutyCompany(idtIndicator.getDutyCompany());
                    relDir.setIdtDatasource(idtIndicator.getDatasource());
                    relDir.setIdtDivisionCode(idtIndicator.getDivisionCode());
                    relDir.setIdtName(idtIndicator.getName());
                    relDir.setIdtScope(idtIndicator.getScope());
                    relDir.setIdtType(idtIndicator.getType());
                    relDir.setIdtUnit(idtIndicator.getUnit());
                    relDir.setName(idtIndicator.getName());
                    calculateResultLit.add(relDir);
                    apiIdtIndicatorsDir.setCalculateResultLit(calculateResultLit);
                    // 加入因子列表
                    relIdtList.add(relDir);
                    relIdtIdList.add( relDir.getIndicatorsId() );
                }
            }
        }

        System.out.println(indicatorsDirLists);
        if (!relIdtIdList.isEmpty()) {
            // 查指标数值
            Map<String, List<ApiIndicatorsVal>> relIdtValMap = iIdtIndicatorsService.mapIdtVal(relIdtIdList, year.toString(), divisionCode, false, false);
            // 填入因子列表
            relIdtList.stream().forEach(relDir->{
                List<ApiIndicatorsVal> apiIndicatorsValList = relIdtValMap.get(relDir.getIndicatorsId());
                relDir.setApiIndicatorsVal(apiIndicatorsValList.isEmpty()? null: apiIndicatorsValList.get(0));
            });
        }

        // 获取所有指标
        List<String> idtIdList = apiIdtIndicatorsDirs.stream().filter(idtDir -> {
            return idtDir.getType() == 2;
        }).map(ApiIdtIndicatorsDir::getIndicatorsId).collect(Collectors.toList());
        // 查指标数值
        Map<String, List<ApiIndicatorsVal>> idtValMap = iIdtIndicatorsService.mapIdtVal(idtIdList, year.toString(), divisionCode, false, false);
        // 填入对象中
        fhzbList.forEach(idtDir -> {
            List<ApiIndicatorsVal> apiIndicatorsValList = idtValMap.get(idtDir.getIndicatorsId());
            ApiIndicatorsVal apiIndicatorsVal = apiIndicatorsValList.get(0);
            // 20210806 指标预警添加预警状态
            if(org.apache.commons.lang.StringUtils.isNotBlank(apiIndicatorsVal.getWarnRuleConfig())){
                String warnStatus = iIdtIndicatorsService.updateWarnStatus(apiIndicatorsVal);
                apiIndicatorsVal.setWarnStatus(warnStatus);
            }else {
                apiIndicatorsVal.setWarnStatus("null,尚未配置规则");
            }
            idtDir.setApiIndicatorsVal(apiIndicatorsValList.isEmpty()? null: apiIndicatorsValList.get(0));
        });
        //创建树形结构
        List indicatorsDirListsTree = createTree(one.getId(), indicatorsDirLists);
        //定义文件存放路径
        String docxFileUrl = null;
        //定义两个输入流,一个用于写入文件内容到word,另一个用于文件下载
        InputStream inputStream1 = null;
        InputStream inputStream2 = null;
        try{
            // 文件名
            String newExportFileName = year.toString()+ "年" + divisionText+"城市体检评估报告" ;
            // 查询该体检评估报告是否已存在
            LambdaQueryWrapper<CmeReport> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(CmeReport::getReportName, newExportFileName);
            List<CmeReport> list = cmeReportService.list(queryWrapper);
            if (list.size() > 0) {
                temp = true;
            }else {
                // word文档
                Map<String,Object> docxListInfo = this.exportMonitorWarningReportWord(indicatorsDirListsTree, divisionCode, year);
                docxFileUrl = FileUtil.tempFilePath + docxListInfo.get("docName");
                // 导出
                InputStream inputStream = new FileInputStream(docxFileUrl);
                //下载文件
//                response.setContentType("application/octet-stream;charset=UTF-8;");
//                response.setHeader("Content-Disposition", "attachment; filename=\"" +  new String(newExportFileName.getBytes(),"iso-8859-1") + ".docx"+ "\"");
//                ServletOutputStream outputStream = response.getOutputStream();
//                byte[] bytes = new byte[1024];
//                int len = 0;
//                while ((len = inputStream.read(bytes)) > 0){
//                    outputStream.write(bytes,0,len);
//                }
                cmeReport.setDivisionName(divisionText);
                cmeReport.setDivisionCode(divisionCode);
                cmeReport.setReportName(newExportFileName);
                cmeReport.setYear(year.toString());
                cmeReport.setTypeValue("本报告包含" + docxListInfo.get("zbSize") + "项体检指标");
                uploadWordAndPdf(inputStream, cmeReport, docxFileUrl);
                inputStream.close();
//                outputStream.flush();
//                outputStream.close();
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(docxFileUrl != null){
                FileUtil.deleteFile(docxFileUrl);
            }
            if(inputStream1 !=null){
                inputStream1.close();
            }
            if(inputStream2 !=null){
                inputStream2.close();
            }
        }
        return temp;
    }



    public void uploadWordAndPdf(InputStream inputStream,CmeReport cmeReport,String docxFileUrl) throws IOException {

        //由于操作异常后删除文件
        List<String> tempSavePathList = new ArrayList<>();
        File tempDocFile = null;
        File tempPdfFile = null;
        try {
            String uuid = UuidUtil.get32UUID();
            //上传 word 文件
            String docUrl = MinioUtil.uploadFile(inputStream,"体检评估报告/" + uuid, cmeReport.getReportName()+ ".docx");
            tempSavePathList.add(docUrl);
            //将 MultipartFile 转成 FiLE
            tempDocFile = new File(docxFileUrl);
            tempPdfFile = File.createTempFile(cmeReport.getReportName(), ".pdf");
            //将 word 转成 pdf
            WordUtil.doc2pdf(tempDocFile, tempPdfFile);
            //上传 pdf
            String pdfUrl = MinioUtil.uploadFile(new FileInputStream(tempPdfFile),"体检评估报告/" + uuid,cmeReport.getReportName() + ".pdf");
            tempSavePathList.add(pdfUrl);
            //保存文件信息
            cmeReport.setId(uuid);
            cmeReport.setWordFilePath(docUrl);
            cmeReport.setPdfFilePath(pdfUrl);
            this.save(cmeReport);
        } catch (IOException e) {
                if(docxFileUrl != null){
                    FileUtil.deleteFile(docxFileUrl);
                }
                MinioUtil.batchRemoveFile(tempSavePathList);
                e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }




    @Override
    public void uploadFile(CmeReport cmeReport,MultipartFile file) throws IOException {

        //由于操作异常后删除文件
        List<String> tempSavePathList = new ArrayList<>();
        File tempDocFile = null;
        File tempPdfFile = null;
        try {
            //保存体检报告文件信息
            //获取文件名
            String fileName = file.getOriginalFilename();
            //文件名去除后缀
            String filename = fileName.substring(0, fileName.lastIndexOf("."));
            //获取文件类型,判断是否是 word
            String fileType = fileName.substring(fileName.lastIndexOf("."));
            //生成 uuid 用于保存报告信息和上传的文件目录
            String uuid = UuidUtil.get32UUID();
            if (".doc".equalsIgnoreCase(fileType) || ".docx".equalsIgnoreCase(fileType)) {
                //上传 word 文件
                String docUrl = MinioUtil.uploadFile(file.getInputStream(), "体检评估报告/" + uuid, fileName);
                //保存 word 文件上传路径用于操作失败时删除文件
                tempSavePathList.add(docUrl);
                //将 MultipartFile 转成 FiLE
                tempDocFile = multipartFileToFile(file);
                tempPdfFile = File.createTempFile(fileName, ".pdf");
                //将 word 转成 pdf
                WordUtil.doc2pdf(tempDocFile, tempPdfFile);
                //上传 pdf
                String pdfUrl = MinioUtil.uploadFile(new FileInputStream(tempPdfFile),"体检评估报告/" + uuid,filename + ".pdf");
                //保存 pdf 文件上传路径用于操作失败时删除文件
                tempSavePathList.add(pdfUrl);
                //保存报告信息
                cmeReport.setId(uuid);
                cmeReport.setTypeValue("本报告为本地上传报告!");
                cmeReport.setWordFilePath(docUrl);
                cmeReport.setPdfFilePath(pdfUrl);
                this.save(cmeReport);
            }
        } catch (IOException e) {
            MinioUtil.batchRemoveFile(tempSavePathList);
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //String divisionCode, String year, String month, String createTime, String reportName
    @Override
    public Page listByEntity(Page page, String divisionCode, String year, String month, String createTime, String reportName) {
        LambdaQueryWrapper<CmeReport> queryWrapper = (new QueryWrapper()).lambda();
        if (org.apache.commons.lang.StringUtils.isNotBlank(divisionCode)) {
            queryWrapper.like(CmeReport::getDivisionCode, divisionCode);
        }
        if (org.apache.commons.lang.StringUtils.isNotBlank(year)) {
            queryWrapper.apply("to_char(create_time,'YYYY') = '" + year +"'");
        }
        if (org.apache.commons.lang.StringUtils.isNotBlank(month)) {
            queryWrapper.apply("to_char(create_time,'MM') = '" + month +"'");
        }
        if (org.apache.commons.lang.StringUtils.isNotBlank(createTime)) {
            queryWrapper.apply("to_char(create_time,'YYYY-MM-DD') = '" + createTime +"'");
        }
        if (org.apache.commons.lang.StringUtils.isNotBlank(reportName)){
            queryWrapper.like(CmeReport::getReportName, reportName);
        }
        queryWrapper.orderByDesc(CmeReport::getCreateTime);
        page = cmeReportMapper.selectPage(page, queryWrapper);
        List<CmeReport> list = page.getRecords();
        page.setRecords(list);
        return page;
    }


    /**
     * @描述: 生成城市体检评估报告到本地
     * @入参: indicatorsDirList 指标目录列表
     * @入参: divisionCode 行政区划码
     * @入参: year 年份
     * @出参: 报告本地临时文件名, 指标个数
     * @作者: 徐金洲
     * @日期: 2023-04-23
     **/
    private Map<String,Object> generateCmeReportWord(List<IdtEstimateResultDto> IdtEstimateResultDtos, String divisionCode, Integer year, String imageArray ) throws Exception {
        //初始时间
        long startTime = System.currentTimeMillis();
        // 行政区划
        String divisionText = idtMonitorValueService.getNameByDivisionCode(divisionCode);
        // 文档域字段
        List<Map<String, Object>> fieldData = new ArrayList<>(2);
        HashMap<String, Object> docFieldMap = new HashMap<>();
        HashMap<String, Object> docHtmlFieldMap = new HashMap<>();
        fieldData.add(docFieldMap);
        fieldData.add(docHtmlFieldMap);
        // 普通文档域字段
        ArrayList<Object> fieldList = new ArrayList<>();
        HashMap<String, Object> fieldMap = new HashMap<>();
        fieldMap.put("XZQ",divisionText == null? "":divisionText);
        fieldList.add(fieldMap);
        docFieldMap.put("table",fieldList);
        // 文档的html字段
        docHtmlFieldMap.put("type","html");
        List<Map<String, String>> htmlStrList = new ArrayList<>(1);
        docHtmlFieldMap.put("table",htmlStrList);
        HashMap<String, String> htmlStrMap = new HashMap<>(1);
        htmlStrList.add(htmlStrMap);
        // 遍历
        StringBuilder stringBuilder = new StringBuilder("");
        //目录序号
        int itemNum1 = 1;
        //将英文逗号分隔的字符串 id 转成 list
        List<String> imageList = Arrays.asList(imageArray.trim().split(","));

        //定义变量统计指标个数
        int idtnum = 0;
        //遍历树结构获取因子指标名称和检测值,并组装文本信息
        for(int j = 0; j < IdtEstimateResultDtos.size(); j++){
            //获取指标目录名 例如 生态宜居
            String dirName = IdtEstimateResultDtos.get(j).getName();
            String describe = IdtEstimateResultDtos.get(j).getDescribe();
            stringBuilder.append("<h1 style=\"font-family:'宋体';font-size:18px;\">").append("("+ itemNum1++ +")").append(". ").append(dirName).append("</h1>");
            stringBuilder.append("<p style=\"font-family:'宋体';font-size:18px;text-indent:2em;\">")
                    .append(describe).append("</p>");
            //获取指标数据
            List<IdtEstimateResultDto.IdtEstimateResultTable> tables = IdtEstimateResultDtos.get(j).getTables();
            //统计指标个数
            idtnum+= tables.size();
            //拼接 表格并组装数据
            if (tables != null && !tables.isEmpty()) {
                //获取表头的因子指标名
                stringBuilder.append("<table style =\"border-collapse:collapse;border: solid 1px #000;font-family:'宋体';\">")
                        .append("<tr>")
                        .append("<td>序号</td>")
                        .append("<td>指标名称</td>")
                        .append("<td>计算结果</td>")
                        .append("<td>综合评价</td>")
                        .append("<td>评价标准</td>")
                        .append("<td>数据来源</td>")
                        .append("</tr>");
                for(int i = 0; i < tables.size(); i++) {
                    //获取指标名称拼装表格
                    stringBuilder
                            .append("<tr>")
                            .append("<td>").append(i+1).append("</td>")
                            .append("<td>").append(tables.get(i).getIdtName() + "（" + tables.get(i).getIdtUnit() + "）").append("</td>")
                            .append("<td>").append(tables.get(i).getEstimateValue()).append("</td>")
                            .append("<td>").append(tables.get(i).getEstimateStatus()).append("</td>")
                            .append("<td>").append(tables.get(i).getEstimateRule()).append("</td>")
                            .append("<td>").append(tables.get(i).getIdtDataSource()).append("</td>")
                            .append("</tr>");
                }
                stringBuilder.append("</table>");
            }
            //获取图片路径
            String imageUrl = imageList.get(j);
            //插入地图图片
            if(org.apache.commons.lang.StringUtils.isNotBlank(imageUrl)){
                stringBuilder.append("<img style=\"text-align:center;display:table-cell\" src=\"").append(imageUrl).append("\">");
            }
        }
        stringBuilder.insert(0,"<style>table,td,th{font-size:12px;border:1px solid grey;padding:5px;width:555px;text-align:center;}p,span,h1,h2,h3,div{font-family:'宋体';}*{font-family:'宋体';}</style>");
        htmlStrMap.put("html_str",stringBuilder.toString());
        // 加载模板文件
        ClassPathResource resource = new ClassPathResource("template/城市体检评估报告模板.docx");
        InputStream inputStream = resource.getInputStream();
        //进行word打印
        String docx = NewWordUtil.wordprint(inputStream, fieldData, null, null, "docx", "", "", null);
        inputStream.close();
        //获取指标数量 用于保存体检评估报告信息
        Map<String,Object> map = new HashMap();
        map.put("zbSize",idtnum);
        map.put("docName",docx.substring(docx.lastIndexOf("/") + 1, docx.length()));
        //报告生成成功后清除 minio 的地图图片文件
        List<String> imageUrlList = new ArrayList<>();
        if (imageList.size() > 0) {
            for (String imageUrl : imageList) {
                imageUrlList.add(imageUrl);
            }
            MinioUtil.batchRemoveFile(imageUrlList);
        }
        //结束时间
        long endTime = System.currentTimeMillis();
        //打印
        System.out.println("程序运行时间：" + (endTime - startTime) + "ms");
        return map;
    }



    /**
     * @描述: 导出【体检评估预警报告】到本地
     * @入参: indicatorsDirList 指标目录列表
     * @入参: divisionCode 行政区划码
     * @入参: year 年份
     * @出参: 【国土空间规划监测评估预警报告】本地临时文件名
     * @作者: 陈宏成
     * @日期: 2021/01/20
     **/
    private Map<String,Object> exportMonitorWarningReportWord(List<ApiIdtIndicatorsDir> indicatorsDirList, String divisionCode, Integer year ) throws Exception {

        //初始时间
        long startTime = System.currentTimeMillis();

        // 行政区划
        String divisionText = idtMonitorValueService.getNameByDivisionCode(divisionCode);
        // 文档域字段
        List<Map<String, Object>> fieldData = new ArrayList<>(2);
        HashMap<String, Object> docFieldMap = new HashMap<>();
        HashMap<String, Object> docHtmlFieldMap = new HashMap<>();
        fieldData.add(docFieldMap);
        fieldData.add(docHtmlFieldMap);
        // 普通文档域字段
        ArrayList<Object> fieldList = new ArrayList<>();
        HashMap<String, Object> fieldMap = new HashMap<>();
        fieldMap.put("XZQ",divisionText == null? "":divisionText);
        fieldList.add(fieldMap);
        docFieldMap.put("table",fieldList);
        // 文档的html字段
        docHtmlFieldMap.put("type","html");
        List<Map<String, String>> htmlStrList = new ArrayList<>(1);
        docHtmlFieldMap.put("table",htmlStrList);
        HashMap<String, String> htmlStrMap = new HashMap<>(1);
        htmlStrList.add(htmlStrMap);
        // 遍历
        SimpleDateFormat formatter= new SimpleDateFormat("yyyy年MM月");
        Date date = new Date(System.currentTimeMillis());
        String years = formatter.format(date);
        StringBuilder stringBuilder = new StringBuilder("");
        //目录序号
        int itemNum1 = 1;
        //指标序号
        int itemNum2 = 1;
        List<ApiIdtIndicatorsDir> fhzbList = null;
        List<ApiIdtIndicatorsDir> yzzbList = null;
        //遍历树结构获取因子指标名称和检测值,并组装文本信息
        for(ApiIdtIndicatorsDir apiIdtIndicatorsDir : indicatorsDirList){
            //初始化map集合存放因子指标名称
            //获取指标目录名 例如 生态宜居
            String dirname = apiIdtIndicatorsDir.getName();
            stringBuilder.append("<h1 style=\"font-family:'宋体';font-size:18px;\">").append("("+ itemNum1++ +")").append(". ").append(dirname).append("</h1>");
            //保存复合指标在当前行政区下的检测值数据
            List<ApiIndicatorsVal> getIndicatorsValList = null;
            //保存复合指标各个行政区下的监测值数据
            List<ApiIndicatorsVal> subDivisionIndicatorsValList = null;
            //获取符合指标名称
            //List<ApiIdtIndicatorsDir> fhzbList = apiIdtIndicatorsDir.getChildren();
            fhzbList = apiIdtIndicatorsDir.getChildren();
            for(ApiIdtIndicatorsDir fhzbdir : fhzbList){
                String fhzbname = fhzbdir.getIdtName();
                stringBuilder.append("<h2 style=\"font-family:'宋体';font-size:18px;\">").append(itemNum2++).append(". ").append(fhzbname).append("</h2>");
                stringBuilder.append("<p style=\"font-family:'宋体';font-size:18px;text-indent:2em;\">").append("截止至").append(years);
                //查询当前行政区的指标值
                getIndicatorsValList = getIndicatorsValList(divisionCode,year,fhzbdir.getIndicatorsId());
                //查询当前行政区子级行政区的指标数值
                subDivisionIndicatorsValList = subDivisionIndicatorsValList(divisionCode,year,fhzbdir.getIndicatorsId());
                //保存因子指标的名称和监测值,单位
                String yzzbname = "";
                String monitorValue = "";
                String unit = "";
                //保存复合指标在当前行政去下的检测值数据
                List<ApiIndicatorsVal> getIndicatorsValList1 = null;
                //保存因子指标各个行政区下的监测值数据
                List<ApiIndicatorsVal> subDivisionIndicatorsValList1 = null;
                //List<ApiIdtIndicatorsDir> yzzbList = fhzbdir.getCalculateResultLit();
                yzzbList = fhzbdir.getCalculateResultLit();
                for(ApiIdtIndicatorsDir yzzbdir : yzzbList){
                    yzzbname = yzzbdir.getName();
                    //获取因子指标检测值和单位
                    ApiIndicatorsVal apiIndicatorsVal = yzzbdir.getApiIndicatorsVal();
                    monitorValue = apiIndicatorsVal.getMonitorValue();
                    unit = yzzbdir.getIdtUnit();
                    stringBuilder.append(",").append(yzzbname).append(monitorValue==null?" ":monitorValue).append(unit==null?" ":unit);
                    //查询当前行政区子级行政区的指标数值
                    subDivisionIndicatorsValList1 = subDivisionIndicatorsValList(divisionCode,year,yzzbdir.getIndicatorsId());
                    //查询当前因子指标的检测值数据
                    getIndicatorsValList1 = getIndicatorsValList(divisionCode,year,yzzbdir.getIndicatorsId());
                    //合并复合指标值和因子指标值数据(各个行政区的)
                    subDivisionIndicatorsValList.addAll(subDivisionIndicatorsValList1);
                    //合并因子指标值(当前行政区的)
                    getIndicatorsValList.addAll(getIndicatorsValList1);
                }
                //文本内容拼接结束
                stringBuilder.append(",").append(yzzbname).append(monitorValue==null?" ":monitorValue).append(unit==null?" ":unit).append("，").append("占").append(yzzbname).append("73%").append("</p>");
                //根据行政区划分组组装表格数据
                Map<String, List<ApiIndicatorsVal>> collect = subDivisionIndicatorsValList.stream().collect(Collectors.groupingBy(ApiIndicatorsVal::getDivisionName));
                List<ApiYzIndicatorsVal> ZbListData = new ArrayList();
                for(String key : collect.keySet()){
                    ApiYzIndicatorsVal apiYzIndicatorsVals = new ApiYzIndicatorsVal();
                    String xzqName = key;
                    List<ApiIndicatorsVal> value = collect.get(key);
                    int temp = 0;
                    for(ApiIndicatorsVal apiIndicatorsVal : value){
                        String zbname = apiIndicatorsVal.getName();
                        String monitorValues = apiIndicatorsVal.getMonitorValue();
                        String xzqCode = apiIndicatorsVal.getDivisionCode();
                        String units = apiIndicatorsVal.getUnit();
                        if(temp == 0){
                            apiYzIndicatorsVals.setFhzbName(zbname);
                            apiYzIndicatorsVals.setFhzbVal(monitorValues);
                            apiYzIndicatorsVals.setFhzbValUnit(units);
                        }else if(temp == 1){
                            apiYzIndicatorsVals.setYzzbName1(zbname);
                            apiYzIndicatorsVals.setYzzbVal1(monitorValues);
                            apiYzIndicatorsVals.setYzzbValUnit1(units);
                        }else if(temp == 2){
                            apiYzIndicatorsVals.setYzzbName2(zbname);
                            apiYzIndicatorsVals.setYzzbVal2(monitorValues);
                            apiYzIndicatorsVals.setYzzbValUnit2(units);
                        }
                        apiYzIndicatorsVals.setDivisionName(xzqName);
                        apiYzIndicatorsVals.setDivisionCode(xzqCode);
                        temp++;
                    }
                    ZbListData.add(apiYzIndicatorsVals);
                    temp = 0;
                }

                //获取合计指标的数据
                Map<String, List<ApiIndicatorsVal>> collect1 = getIndicatorsValList.stream().collect(Collectors.groupingBy(ApiIndicatorsVal::getDivisionName));
                List<ApiAllIndicatorsVal> AllZbListData = new ArrayList();
                for(String key : collect1.keySet()){
                    ApiAllIndicatorsVal apiAllIndicatorsVal = new ApiAllIndicatorsVal();
                    String xzqName = key;
                    List<ApiIndicatorsVal> value = collect1.get(key);
                    int temp = 0;
                    for(ApiIndicatorsVal apiIndicatorsVal : value){
                        String zbname = apiIndicatorsVal.getName();
                        String monitorValues = apiIndicatorsVal.getMonitorValue();
                        String xzqCode = apiIndicatorsVal.getDivisionCode();
                        if(temp == 0){
                            apiAllIndicatorsVal.setFhzbAllName(zbname);
                            apiAllIndicatorsVal.setFhzbAllVal(monitorValues);
                        }else if(temp == 1){
                            apiAllIndicatorsVal.setYzzbAllName1(zbname);
                            apiAllIndicatorsVal.setYzzbAllVal1(monitorValues);
                        }else if(temp == 2){
                            apiAllIndicatorsVal.setYzzbAllName2(zbname);
                            apiAllIndicatorsVal.setYzzbVaAlll2(monitorValues);
                        }
                        apiAllIndicatorsVal.setDivisionName(xzqName);
                        apiAllIndicatorsVal.setDivisionCode(xzqCode);
                        temp++;
                    }
                    AllZbListData.add(apiAllIndicatorsVal);
                    temp = 0;
                }

                //拼接 表格并组装数据
                if (ZbListData != null && !ZbListData.isEmpty()){
                        //获取表头的因子指标名称
                        String yzzbMc1 = "";
                        String yzzbMc2 = "";
                        String fhzbMc = "";
                        for(ApiYzIndicatorsVal apiYzIndicatorsVals : ZbListData){
                            yzzbMc1 = apiYzIndicatorsVals.getYzzbName1();
                            yzzbMc2 = apiYzIndicatorsVals.getYzzbName2();
                            fhzbMc = apiYzIndicatorsVals.getFhzbName();
                        }
                        stringBuilder.append("<table style =\"border-collapse:collapse;border: solid 1px #000;font-family:'宋体';\">")
                            .append("<tr>")
                            .append("<td>行政区</td>")
                            .append("<td>").append(yzzbMc1).append("</td>")
                            .append("<td>").append(yzzbMc2).append("</td>")
                            .append("<td>").append(fhzbMc).append("</td>")
                            .append("</tr>");
                    for(ApiYzIndicatorsVal apiYzIndicatorsVals : ZbListData) {
                        stringBuilder
                            .append("<tr>")
                            .append("<td>").append(apiYzIndicatorsVals.getDivisionName()).append("</td>")
                            .append("<td>").append(apiYzIndicatorsVals.getYzzbVal1()).append("</td>")
                            .append("<td>").append(apiYzIndicatorsVals.getYzzbVal2()).append("</td>")
                            .append("<td>").append(apiYzIndicatorsVals.getFhzbVal()).append("</td>")
                            .append("</tr>");
                    }
                    for(ApiAllIndicatorsVal apiAllIndicatorsVal : AllZbListData){
                        stringBuilder
                            .append("<tr>")
                            .append("<td>").append("合计").append("</td>")
                            .append("<td>").append(apiAllIndicatorsVal.getYzzbAllVal1() == null?"":apiAllIndicatorsVal.getYzzbAllVal1()).append("</td>")
                            .append("<td>").append(apiAllIndicatorsVal.getYzzbVaAlll2() == null?"":apiAllIndicatorsVal.getYzzbVaAlll2()).append("</td>")
                            .append("<td>").append(apiAllIndicatorsVal.getFhzbAllVal() == null?"":apiAllIndicatorsVal.getFhzbAllVal()).append("</td>")
                            .append("</tr>");
                    }
                    stringBuilder.append("</table>");
                }

                stringBuilder.append("<p style=\"text-align:center;font-family:'宋体';\">表1-").append(itemNum2).append(fhzbname).append("统计表</p>\n");
                //构建 echart 图表
                Map<String, Object> dataMap = new HashMap<>();
                String echartsHtml = buildMonitorWarningReportWordHtml(fhzbdir,dataMap,divisionCode,year);
                stringBuilder.append(echartsHtml);
                // 处理html图片的预留埋点
                Map<String,String> echartOptions = (Map<String,String>)dataMap.getOrDefault("echartOptions", new HashMap<>());
                this.replaceEchartImgForHtml(echartOptions,stringBuilder);
                stringBuilder.append("<p style=\"text-align:center;font-family:'宋体';\">图1-").append(itemNum2).append(fhzbname).append("柱状图</p>\n");
            }
            itemNum2 = 1;
        }

        //结束时间
        long endTime = System.currentTimeMillis();
        //打印
        System.out.println("程序运行时间：" + (endTime - startTime) + "ms");

        stringBuilder.insert(0,"<style>table,td,th{font-size:12px;border:1px solid grey;padding:5px;width:555px;text-align:center;}p,span,h1,h2,h3,div{font-family:'宋体';}*{font-family:'宋体';}</style>");
        htmlStrMap.put("html_str",stringBuilder.toString());
        // 加载模板文件
        ClassPathResource resource = new ClassPathResource("template/城市体检评估模板.docx");
        InputStream inputStream = resource.getInputStream();
        //进行word打印
        String docx = NewWordUtil.wordprint(inputStream, fieldData, null, null, "docx", "", "", null);
        inputStream.close();
        //获取指标数量 用于保存体检评估报告信息
        Map<String,Object> map = new HashMap();
        int zbSize = fhzbList.size() + yzzbList.size();
        map.put("zbSize",zbSize);
        map.put("docName",docx.substring(docx.lastIndexOf("/") + 1, docx.length()));
        return map;
        //return docx.substring(docx.lastIndexOf("/") + 1, docx.length());
    }


    //加载 echart 模板文件拼接 echart 埋点
    private String buildMonitorWarningReportWordHtml(ApiIdtIndicatorsDir indicatorsDir,Map<String, Object> dataMap,String divisionCode,Integer year){

        StringBuilder stringBuilder = new StringBuilder();
        //查询当前行政区子级行政区的指标数值
        List<ApiIndicatorsVal> divisionIndicatorsValList = subDivisionIndicatorsValList(divisionCode,year,indicatorsDir.getIndicatorsId());
        // 构建echart图表
        // 获取option配置文件内容
        List<ApiMapDivision> apiMapDivisions = idtMonitorValueService.listDirectChildDivision(divisionCode);
        String option = (String) dataMap.get( "chartOptionFtlStr" );
        if (!StringUtils.hasText(option)){
            ClassPathResource resource = new ClassPathResource("template/bar_option.ftl" );
            try {
                InputStream inputStream = resource.getInputStream();
                option = FileUtil.txt2String(inputStream, "utf-8");
            }catch (Exception e){
                throw new RuntimeException("加载option.ftl文件失败", e);
            }
            dataMap.put("chartOptionFtlStr", option);
        }
        option = option.replace("${DivisionName}",JSON.toJSONString(apiMapDivisions.stream().map(ApiMapDivision::getName).collect(Collectors.toList())));
        option = option.replace("${MonitorValues}",JSON.toJSONString(divisionIndicatorsValList.stream().map(ApiIndicatorsVal::getMonitorValue).collect(Collectors.toList())));
        //option = option.replace("${targetValue}",JSON.toJSONString(divisionIndicatorsValList.stream().map(ApiIndicatorsVal::getTargetValue).collect(Collectors.toList())));
        option = option.replace("${WarnStatus}",JSON.toJSONString(divisionIndicatorsValList.stream().map(ApiIndicatorsVal::getWarnStatus).collect(Collectors.toList())));
        // 将图表结果暂存
        Map<String,String> echartOptions = (Map<String,String>)dataMap.get("echartOptions");
        if (echartOptions == null){
            echartOptions = new HashMap<>();
            dataMap.put("echartOptions",echartOptions);
        }
        echartOptions.put(indicatorsDir.getIndicatorsId(), option);
        // 在html中预留埋点，方便后面直接替换
        stringBuilder.append("<img data-id=\"").append(indicatorsDir.getIndicatorsId()).append("\">");
        return stringBuilder.toString();
    }


    /**
     * @描述: 查询当前行政区下自行政区的指标值
     * @入参:
     * @出参:
     * @作者: 徐金洲
     * @日期: 2023-04-10
     **/
    public List<ApiIndicatorsVal> subDivisionIndicatorsValList(String divisionCode,Integer year,String indicatorsId){
        // 查询当前行政区子级行政区
        List<ApiMapDivision> apiMapDivisions = idtMonitorValueService.listDirectChildDivision(divisionCode);
        String subDivisionCodes = apiMapDivisions.stream().map(ApiMapDivision::getCode).collect(Collectors.joining(","));
        List<ApiIndicatorsVal> subDivisionIndicatorsValList = iIdtIndicatorsService.listSingleIdtVal(indicatorsId,year+"",subDivisionCodes,false,false);
        subDivisionIndicatorsValList.stream().forEach(val->{
            Optional<ApiMapDivision> mapDivision = apiMapDivisions.stream().filter(division -> division.getCode().equals(val.getDivisionCode())).findAny();
            val.setDivisionName(mapDivision.isPresent()? mapDivision.get().getName(): "");
            val.setValue(this.holdTwoDecimal(val.getValue()));
            val.setTargetValue(this.holdTwoDecimal(val.getTargetValue()));
            val.setBaseValue(this.holdTwoDecimal(val.getBaseValue()));
            val.setMonitorValue(this.holdTwoDecimal(val.getMonitorValue()));
        });
        return subDivisionIndicatorsValList;
    }

    /**
     * @描述: 查询当前行政区下的指标值
     * @入参:
     * @出参:
     * @作者: 徐金洲
     * @日期: 2023-04-10
     **/
    public List<ApiIndicatorsVal> getIndicatorsValList(String divisionCode,Integer year,String indicatorsId){
        List<ApiIndicatorsVal> getIndicatorsValList = iIdtIndicatorsService.listSingleIdtVal(indicatorsId,year+"",divisionCode,false,false);
        return getIndicatorsValList;
    }

    /**
     * @描述:递归创建树
     * @入参:
     * @出参:
     * @作者: 郑文彬
     * @日期: 2020/4/20 17:30
     **/
    public static List createTree(String parentId, List<ApiIdtIndicatorsDir> menus) {
        List tree = new ArrayList<>();
        for (int i = 0; i < menus.size(); i++) {
            ApiIdtIndicatorsDir idtDirectory = menus.get(i);
            if (idtDirectory.getParentId().equals(parentId)) {
                tree.add(idtDirectory);
                List children = createTree(idtDirectory.getId(), menus);
                if (children != null && !children.isEmpty()) {
                    idtDirectory.setChildren(children);
                } else {
                    idtDirectory.setChildren(new ArrayList<>());
                }
            }
        }
        return tree;
    }


    /***
     * 将html中预留的echars图片埋点全部替换成图片base64，注意：html中的埋点为以下格式： <img data-id="id">  。id值可以使模型id，也可以是其他的唯一id，要和 echartOptions 参数中的 key 能对应上。
     * @入参: echartOptions echarts的option完整配置，已经装填好数据的那种，key为埋点<img data-id="id">的id的值
     * @入参: stringBuilder html字符串
     * @出参: 图片替换成base64后的html
     * @作者: 陈宏成
     * @日期: 2021/02/04
     */
    private StringBuilder replaceEchartImgForHtml(Map<String,String> echartOptions, StringBuilder stringBuilder){
        if (echartOptions.isEmpty()){
            return stringBuilder;
        }
        echartOptions.entrySet().parallelStream().forEach(entry->{
            String id = entry.getKey();
            String option = entry.getValue();
            String base64Str = null;
            try {
                String eChartPath = EchartGenerateUtil.generateEChart(option);
                base64Str = ByteToFileUtils.encodeBase64File(eChartPath);
                //删除文件
                FileUtil.deleteFile(eChartPath);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                // 如果图片存在，替换html埋点
                String imgHtml = "";
                if (StringUtils.hasText(base64Str)){
                    imgHtml = "<img style=\"text-align:center;display:table-cell\" src=\"data:image/png;base64," + base64Str + "\">";
                }
                String imgBuriedPointStr  = "<img data-id=\"" + id + "\">";
                synchronized (stringBuilder){
                    int imgIndexStart = stringBuilder.indexOf(imgBuriedPointStr);
                    int imgIndexend = imgIndexStart + imgBuriedPointStr.length();
                    stringBuilder.replace(imgIndexStart,imgIndexend,imgHtml);
                }
            }
        });
        return stringBuilder;
    }


    /**
     * @描述: 保留两位小数
     * @入参: value 原字符串
     * @出参: 如果value为空，返回空字符串，否则保留两位小数
     * @作者: 陈宏成
     * @日期: 2021/01/14
     **/
    private String holdTwoDecimal(String value){
        if(!StringUtils.hasText(value)){
            return "";
        }
        return ConvertUtil.formatNumber(Double.valueOf(value), 2);
    }


    public File multipartFileToFile(MultipartFile file) throws Exception {
        File toFile = null;
        if (file.equals("") || file.getSize() <= 0) {
            file = null;
        } else {
            InputStream ins = null;
            ins = file.getInputStream();
            toFile = new File(file.getOriginalFilename());
            inputStreamToFile(ins, toFile);
            ins.close();
        }
        return toFile;

    }



    private static void inputStreamToFile(InputStream ins, File file) {
        try {
            OutputStream os = new FileOutputStream(file);
            int bytesRead = 0;
            byte[] buffer = new byte[8192];
            while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
            os.close();
            ins.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


}
